home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Moscow ML 1.31 / source code / mosml / src / mosmllib / PP.sig < prev    next >
Encoding:
Text File  |  1996-07-03  |  6.6 KB  |  175 lines  |  [TEXT/R*ch]

  1. (* PP -- from the SML/NJ library *)
  2.  
  3. type ppconsumer = {consumer  : string -> unit,
  4.                    linewidth : int,
  5.                    flush     : unit -> unit}
  6.  
  7. datatype break_style = 
  8.     CONSISTENT
  9.   | INCONSISTENT
  10.  
  11. val mk_ppstream    : ppconsumer -> ppstream
  12. val dest_ppstream  : ppstream -> ppconsumer
  13. val add_break      : ppstream -> int * int -> unit
  14. val add_newline    : ppstream -> unit
  15. val add_string     : ppstream -> string -> unit
  16. val begin_block    : ppstream -> break_style -> int -> unit
  17. val end_block      : ppstream -> unit
  18. val clear_ppstream : ppstream -> unit
  19. val flush_ppstream : ppstream -> unit
  20. val with_pp        : ppconsumer -> (ppstream -> unit) -> unit
  21. val pp_to_string   : int -> (ppstream -> 'a -> unit) -> 'a -> string
  22.  
  23. (*  This unit provides tools for creating customized Oppen-style
  24.     pretty-printers, based on the type ppstream.  A ppstream is an
  25.     output stream that contains prettyprinting commands.  The commands
  26.     are placed in the stream by various function calls listed below.
  27.  
  28.     There following primitives add commands to the stream:
  29.     begin_block, end_block, add_string, add_break, and add_newline.
  30.     All calls to add_string, add_break, and add_newline must happen
  31.     between a pair of calls to begin_block and end_block must be
  32.     properly nested dynamically.  All calls to begin_block and
  33.     end_block must be properly nested (dynamically).
  34.  
  35.     A ppconsumer is a record 
  36.                   {consumer  : string -> unit,
  37.                    linewidth : int,
  38.                    flush     : unit -> unit}
  39.     of a string consumer, a specified linewidth, and a flush function
  40.     which is called whenever flush_ppstream is called.
  41.  
  42.     A prettyprinter can be called outright to print a value.  In
  43.     addtion, any prettyprinter for a nullary datatype ty can be
  44.     installed in the top-level system, so that all values of that type
  45.     will be printed in 
  46.  
  47.     [type break_style] determines the way a block is broken into
  48.     lines.  Style CONSISTENT means that if any line break occurs
  49.     inside the block, then all indicated line breaks occur.  Style
  50.     INCONSISTENT means that breaks will be inserted to only to avoid
  51.     overfull lines.
  52.  
  53.     [mk_ppstream {consumer, linewidth, flush}] creates a new ppstream
  54.     which invokes the consumer to output text, putting at most
  55.     linewidth characters on each line.
  56.  
  57.     [dest_ppstream ppstrm] extracts the linewidth, flush function, and
  58.     consumer from a ppstream.
  59.  
  60.     [add_break ppstrm (size, offset)] notifies the pretty-printer that
  61.     a line break is possible at this point.  
  62.     * When the current block style is CONSISTENT:
  63.        ** if the entire block fits on the remainder of the line, then
  64.           output size spaces; else
  65.        ** increase the current indentation by the block offset;
  66.           further indent every item of the block by offset, and add
  67.           one newline at every add_break in the block.
  68.     * When the current block style is INCONSISTENT:
  69.        ** if the next component of the block fits on the remainder of
  70.           the line, then output size spaces; else
  71.        ** issue a newline and indent to the current indentation level
  72.           plus the block offset plus the offset.
  73.  
  74.     [add_newline ppstrm] issues a newline.
  75.  
  76.     [add_string ppstrm str] outputs the string str to the ppstream.
  77.  
  78.     [begin_block ppstrm style blockoffset] begins a new block and
  79.     level of indentation, with the given style and block offset.
  80.  
  81.     [end_block ppstrm] closes the current block.  
  82.  
  83.     [clear_ppstream ppstrm] restarts the stream, without affecting the
  84.     underlying consumer.
  85.  
  86.     [flush_ppstream ppstrm] executes any remaining commands in the
  87.     ppstream (that is, flushes currently accumulated output to the
  88.     consumer associated with ppstrm); executes the flush function
  89.     associated with the consumer; and calls clear_ppstream.
  90.  
  91.     [with_pp consumer f] makes a new ppstream from the consumer and
  92.     applies f (which can be thought of as a producer) to that
  93.     ppstream, then flushed the ppstream and returns the value of f.
  94.  
  95.     [pp_to_string linewidth printit x] constructs a new ppstream
  96.     ppstrm whose consumer accumulates the output in a string s.  Then
  97.     evaluates (printit ppstrm x) and finally returns the string s.
  98.  
  99.     
  100.     Example 1: Define a prettyprinter for Booleans:
  101.  
  102.         load "PP";
  103.         fun ppbool pps d = 
  104.             let open PP
  105.             in
  106.                 begin_block pps INCONSISTENT 6; 
  107.                 add_string pps (if d then "right" else "wrong");
  108.                 end_block pps
  109.             end
  110.  
  111.     Now one may define a ppstream to print to, and exercise it:
  112.  
  113.         val ppstrm = PP.mk_ppstream {consumer  = outputc std_out, 
  114.                                      linewidth = 72,
  115.                                      flush     = fn () => flush_out std_out};
  116.  
  117.         fun ppb b = (ppbool ppstrm b; PP.flush_ppstream ppstrm);
  118.  
  119.         - ppb false;
  120.         wrong> val it = () : unit   
  121.  
  122.     The prettyprinter may also be installed in the toplevel system;
  123.     then it will be used to print all expressions of type bool
  124.     subsequently computed:
  125.  
  126.         - installPP ppbool;
  127.         > val it = () : unit
  128.         - 1=0;
  129.         > val it = wrong : bool
  130.         - 1=1;
  131.         > val it = right : bool
  132.  
  133.     See library Meta for a description of installPP.
  134.  
  135.  
  136.     Example 2: Prettyprinting simple expressions (file examples/ppexpr.sml)
  137.  
  138.         datatype expr = 
  139.             Cst of int 
  140.           | Neg of expr
  141.           | Plus of expr * expr
  142.  
  143.         fun ppexpr pps e0 = 
  144.             let open PP
  145.                 fun ppe (Cst i)        = add_string pps (Integer.toString i)
  146.                   | ppe (Neg e)        = (add_string pps "~"; ppe e)
  147.                   | ppe (Plus(e1, e2)) = (begin_block pps CONSISTENT 0;
  148.                                           add_string pps "(";
  149.                                           ppe e1; 
  150.                                           add_string pps " + ";
  151.                                           add_break pps (0, 1);
  152.                                           ppe e2; 
  153.                                           add_string pps ")";
  154.                                           end_block pps)
  155.             in
  156.                 begin_block pps INCONSISTENT 0; 
  157.                 ppe e0;
  158.                 end_block pps
  159.             end
  160.  
  161.         val _ = installPP ppexpr;
  162.  
  163.         (* Some example values: *)
  164.  
  165.         val e1 = Cst 1;
  166.         val e2 = Cst 2;
  167.         val e3 = Plus(e1, Neg e2);
  168.         val e4 = Plus(Neg e3, e3);
  169.         val e5 = Plus(Neg e4, e4);
  170.         val e6 = Plus(e5, e5);
  171.         val e7 = Plus(e6, e6);
  172.         val e8 = 
  173.             Plus(e3, Plus(e3, Plus(e3, Plus(e3, Plus(e3, Plus(e3, e7))))));
  174. *)
  175.